package edu.gu.hajo.gcl.cmd.factory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import edu.gu.hajo.gcl.cmd.ICommand;
import edu.gu.hajo.gcl.cmd.IMutableCommand;
import edu.gu.hajo.gcl.cmd.impl.AddOpCmd;
import edu.gu.hajo.gcl.cmd.impl.EqOpCmd;
import edu.gu.hajo.gcl.cmd.impl.GetsCmd;
import edu.gu.hajo.gcl.cmd.impl.IfCmd;
import edu.gu.hajo.gcl.cmd.impl.IncrCmd;
import edu.gu.hajo.gcl.cmd.impl.LessOpCmd;
import edu.gu.hajo.gcl.cmd.impl.ProcCmd;
import edu.gu.hajo.gcl.cmd.impl.PutsCmd;
import edu.gu.hajo.gcl.cmd.impl.ReturnCmd;
import edu.gu.hajo.gcl.cmd.impl.SetCmd;
import edu.gu.hajo.gcl.cmd.impl.SubOpCmd;
import edu.gu.hajo.gcl.cmd.impl.WhileCmd;
import edu.gu.hajo.gcl.interp.IInterpreter;

/**
 * Factory for commands in language
 * @author hajo
 *
 */
public final class CommandFactory {

	// Use AbstractCmd internally to be able to reuse
	// same object
	private Map<String, IMutableCommand> commands = null;

	private IInterpreter interp;
	public CommandFactory( IInterpreter interp){
		this.interp = interp;
		initCommands();
	}
	
	private void initCommands(){
		commands = new HashMap<String, IMutableCommand >();
		commands.put("puts", new PutsCmd(interp));
		commands.put("set", new SetCmd(interp));
		commands.put("if", new IfCmd(interp));
		commands.put("==", new EqOpCmd(interp));
		commands.put("<", new LessOpCmd(interp));
		commands.put("while", new WhileCmd(interp));
		commands.put("incr", new IncrCmd(interp));
		commands.put("gets", new GetsCmd(interp));
		commands.put("+", new AddOpCmd(interp));
		commands.put("-", new SubOpCmd(interp));
		commands.put("proc", new ProcCmd(interp));
		commands.put("return", new ReturnCmd(interp));
	}
	
	// Expose restricted interfact to rest of application
	public ICommand lookup(List<String> words) {
		IMutableCommand c = commands.get(words.get(0));
		if (c != null) {
			// Away with command name
			words.remove(0);
			// Possible to reuse same objects
			c.set(words);
		} 
		return c;
	}
	
	public void insert( String name, IMutableCommand command){
		commands.put(name, command);
	}
}
